TQ로 SSR처리하기
SSR을 TanstackQuery로 처리하기
2024-07-04
공식문서에서, 서버에서 데이터를 프리패칭하고 queryClient에 제공하는 방법은 2가지 가 존재한다.
- initalData를 사용하는 방법
- Hydration을 사용하는 방법
먼저 initalData를 사용하는 방법에 대해 알아보자. 쿼리에 initalData를 주입하는 방 법은 query옵션에 직접 주입하는 방법과, queryClient의 prefetchQuery,setQueryData 메서드를 사용하는 방법이 있다.
initalData_placeholderData
config.initalData옵션으로 쿼리의 초기 데이터를 설정할 수 있다. 다만 initalData는 캐시에 남는다. 캐시 레벨에서 동작하고, 오직 하나만 존재할 수 있다. 만약 placeholder를 제공하고 싶다면, placeholderData를 사용한다.
cacheLevel_ObserverLevel
둘의 가장 큰 차이는 캐시에 들어가냐? 아니냐? 의 차이이다. initalData의 경우에는 캐시 객체를 만들 때 직접 옵션으로 넣어둔 것을 사용하는 것을 볼 수 있다.
이 캐시 객체는 각 쿼리 키에 대해 존재한다.
이 쿼리 키로 애플리케이션에서 전역적으로 동일한 데이터를 관리하게 도와주고, 쿼리 키당 하나의 엔트리만 존재하기 떄문에, staleTime, cacheTime에 따라 stale, GC에 의 해 수거되는 시간을 알 수 있다.
반면 Observer level같은 경우 하나의 쿼리 레벨에 생성된 구독을 의미한다. 캐시 레 벨단에서의 변경 사항을 확인하고, 변경사항이 있다면 알림을 받는다 (이 역할을 notifymanager가 한다.!)
이 observer는 useQuery훅을 호출할 떄마다 생긴다. 즉 동일한 캐시를 바라보는 여러 옵저버가 존재할 수 있다.
initalData는 cache Level에서, placeholderData는 Observer Level에서 돌아간다 !
초기설정
먼저 QueryClient를 선언해주어야 한다. Providers폴더에 Query부분에서 queryClient.tsx를 만들었다.
그리고 이 queryClient를 단 한번만 생성하고, 다시 사용하기 위해 싱글톤 형태로 queryClient를 만들어준다.
왜 싱글톤 형식으로 만들어야만 할까!
사용자별로, 다른 분리된 상태를 유지하고, 요청당 하나의 QueryClient를 유지하기 위 해서이다.
이렇게 하고 App Router의 layout파일에서 선언한 Providers로 감싸주면 모든 준비가 끝난다.
initalData
tanstack-query는 SSG와 SSR모두에서 pre-rendering을 제공한다.
기본적으로, initalData는 staleTime의 영향을 받는다. 만약 initalData를 넣어두고, staleTime을 0으로 잡아두면 (기본값으로), 마운트 되자마자 리패칭을 한다.
만약 이번에는 staleTime을 1000으로 두면, 1초 동안 이 데이터는 신선한 상태가 되고 , 1초동안은 다시 데이터를 패칭하지 않는다. 만약 1초가 지나면 stale 상태로 간주되 어, 필요 시 다시 패칭된다.
app router에서 initalData를 사용하는 방법은 서버 컴포넌트에서 데이터를 프리패칭 하고 클라이언트 컴포넌트에 initalData를 props로 전달하는 것이다.
이 방법은 빠르게 설정할 수 있고, 필요에 따라 initalData의 props Drilling이 발생 할 수 있다.
Hydration,Dehydrate
서버에서 데이터를 호출하고 , 클라이언트에 보낼 때 hydration하는 것이다. 그럼 dehydrate와 hydration을 살펴보자.
dehydrate : 서버에서 클라이언트로 전송할 수 있는 형태로 만들기 위해 사용된다. 서 버에서 데이터를 가져오고 이 데이터를 직렬화 해 클라이언트로 전송한다. 직렬화된 데이터는 DehydratedState로 표현되고 hydrate함수를 통해 다시 변환된다.
요기서 직렬화 할 수 없는 것들(함수 등)이 포함되면 serialization에러가 발생한다.
hydrate : 클라이언트에서 직렬화된 상태를 받아서, 서버에서 미리 받은 데이터를 클 라이언트의 쿼리 캐시에 적용해준다.
사용해볼까?
- 먼저 queryClient를 만든다.
- 미리 가져오고 싶은 쿼리에 대해 queryClient.prefetchQuery를 실행한다.
- 이제 dehydrate(queryClient)를 반환한다.
- HydrationBoundary state로 트리를 감싸준다.
먼저 queryClient를 만들고 13버전이기 때문에, layout.tsx에서 queryClient를 감싸주 자!
이제 queryClient를 싱글톤 형식으로 관리하기 위해 getQueryClient라는 함수를 만들 고 queryClient를 한번만 실행되게 만들었다(물론 상황에 따라 queryClient를 여러개 놓고? 관리할 수도 있지 않을까..?)
이제 저 getQueryClient로 queryClient를 가져오고, prefetchQuery를 통해 데이터를 미리 가져와보자!!
나는 블로그 목록에 대해 prefetchQuery를 적용했다. 그럼 실제로 어떻게 불러오는지 확인해보자!
잘 동작하는 것을 볼 수 있다!